package datetype

import (
	"database/sql"
	"database/sql/driver"
	"time"
)

type GormDate time.Time
type GormDateTime time.Time

func NewGormDate(v string) GormDate {
	if tt, err := time.ParseInLocation(FDate, v, time.Local); err == nil {
		return GormDate(tt)
	}
	return GormDate{}
}

func (date *GormDate) Scan(value interface{}) (err error) {
	nullTime := &sql.NullTime{}
	err = nullTime.Scan(value)
	*date = GormDate(nullTime.Time)
	return
}

func (date GormDate) Value() (driver.Value, error) {
	y, m, d := time.Time(date).Date()
	return time.Date(y, m, d, 0, 0, 0, 0, time.Time(date).Location()), nil
}

// GormDataType gorm common data type
func (date GormDate) GormDataType() string {
	return "date"
}

func (date GormDate) GobEncode() ([]byte, error) {
	return time.Time(date).GobEncode()
}

func (date *GormDate) GobDecode(b []byte) error {
	return (*time.Time)(date).GobDecode(b)
}

func (date *GormDate) UnmarshalJSON(b []byte) error {
	if string(b) == "null" {
		return nil
	}
	d, err := time.ParseInLocation(`"`+FDate+`"`, string(b), time.Local)
	*date = GormDate(d)
	return err
}

func (date GormDate) MarshalJSON() ([]byte, error) {
	t := (time.Time)(date)
	b := make([]byte, 0, len(FDate)+2)
	b = append(b, '"')
	b = t.AppendFormat(b, FDate)
	b = append(b, '"')
	return b, nil
}

func (date *GormDateTime) Scan(value interface{}) (err error) {
	nullTime := &sql.NullTime{}
	err = nullTime.Scan(value)
	*date = GormDateTime(nullTime.Time)
	return
}

func (date GormDateTime) Value() (driver.Value, error) {
	return time.Time(date), nil
}

// GormDataType gorm common data type
func (date GormDateTime) GormDataType() string {
	return "datetime"
}

func (date GormDateTime) GobEncode() ([]byte, error) {
	return time.Time(date).GobEncode()
}

func (date *GormDateTime) GobDecode(b []byte) error {
	return (*time.Time)(date).GobDecode(b)
}

func (date *GormDateTime) UnmarshalJSON(b []byte) error {
	if string(b) == "null" {
		return nil
	}
	d, err := time.ParseInLocation(`"`+FDateTime+`"`, string(b), time.Local)
	*date = GormDateTime(d)
	return err
}

func (date GormDateTime) MarshalJSON() ([]byte, error) {
	t := (time.Time)(date)
	b := make([]byte, 0, len(FDateTime)+2)
	b = append(b, '"')
	b = t.AppendFormat(b, FDateTime)
	b = append(b, '"')
	return b, nil
}
